﻿using Common.Unit;
using Quartz;
using Quartz.Impl;
using Quartz.Impl.Triggers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Common.Log;
namespace Joz.TestServer.Quartz
{
    public static class QuartzHelper
    {
        /// <summary>
        /// 缓存任务所在程序集信息
        /// </summary>
        private static Dictionary<string, Assembly> AssemblyDict = new Dictionary<string, Assembly>();

        private static IScheduler scheduler;
        static QuartzHelper()
        {

        }
        /// <summary>
        /// 初始化 
        /// </summary>
        public static void InitScheduler()
        {
            ISchedulerFactory schedulerFactory = new StdSchedulerFactory();
            scheduler = schedulerFactory.GetScheduler();
        }
        /// <summary>
        /// 依据配置文件启动任务
        /// </summary>
        public static void StartScheduler()
        {
            try
            {
                if (!scheduler.IsStarted)
                {
                    //读取数XML文件中的配置，静态缓存
                    var allQuertzXml = TaskXml.allQuertzXml;
                    if (allQuertzXml != null && allQuertzXml.Count > 0)
                    {
                        foreach (var item in allQuertzXml)
                        {
                            try
                            {
                                //依据配置文件，遍历执行任务 
                                ScheduleJob(item);
                            }
                            catch (Exception e)
                            {
                                LogHelper.WriteErrorLog(e.ToString());
                            }
                        }
                    }
                    scheduler.Start();
                }
            }
            catch (Exception ex)
            {
                LogHelper.WriteErrorLog(ex.ToString());
            }
        }
        /// <summary>
        /// 中止所有的任务调度
        /// </summary>
        public static void StopSchedule()
        {
            try
            {
                //判断调度是否已经关闭
                if (!scheduler.IsShutdown)
                {
                    //等待任务运行完成
                    scheduler.Shutdown(true);
                    LogHelper.WriteRecordLog("任务调度停止！");
                }
            }
            catch (Exception ex)
            {
                LogHelper.WriteErrorLog("任务调度停止失败！" + ex.ToString());
            }
        }
        /// <summary>
        /// 启用任务
        /// <param name="task">任务信息</param>
        /// <param name="isDeleteOldTask">是否删除原有任务</param>
        /// <returns>返回任务trigger</returns>
        /// </summary>
        static void ScheduleJob(QuertzXml task)
        {
            //验证是否正确的Cron表达式
            if (ValidExpression(task.CronExpressionString))
            {
                //监测是否存在该任务
                JobKey jk = new JobKey(task.TaskID);
                if (scheduler.CheckExists(jk))
                {
                    scheduler.DeleteJob(jk);
                }

                IJobDetail job = new JobDetailImpl(task.TaskID, GetClassInfo(task.AssemblyName, task.ClassName));
                //添加任务执行参数
                job.JobDataMap.Add("TaskParam", task.TaskParam);

                CronTriggerImpl trigger = new CronTriggerImpl();
                trigger.CronExpressionString = task.CronExpressionString;
                trigger.Name = task.TaskID;
                trigger.Description = task.TaskName;
                scheduler.ScheduleJob(job, trigger);
                if (!task.Status)  //中止任务
                    scheduler.PauseJob(jk);
            }
            else
            {
                throw new Exception(task.CronExpressionString + "不是正确的Cron表达式,无法启动该任务!");
            }
        }
        /// 获取类的属性、方法  
        /// </summary>  
        /// <param name="assemblyName">程序集</param>  
        /// <param name="className">类名</param>  
        static Type GetClassInfo(string assemblyName, string className)
        {
            try
            {
                assemblyName = Common.Unit.FileHelper.GetAbsolutePath(assemblyName + ".dll");
                Assembly assembly = null;
                if (!AssemblyDict.TryGetValue(assemblyName, out assembly))
                {
                    assembly = Assembly.LoadFrom(assemblyName);
                    AssemblyDict[assemblyName] = assembly;
                }
                Type type = assembly.GetType(className, true, true);
                return type;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 校验字符串是否为正确的Cron表达式
        /// </summary>
        /// <param name="cronExpression">带校验表达式</param>
        /// <returns></returns>
        static bool ValidExpression(string cronExpression)
        {
            return CronExpression.IsValidExpression(cronExpression);
        }
    }
}
